package sis.security;/*
 * @auther 顶风少年
 * @mail dfsn19970313@foxmail.com
 * @date 2019-07-31 10:29
 * @notify
 * @version 1.0
 */

import junit.framework.TestCase;
import sis.security.AccountFactory;
import sis.security.Accountable;
import sis.security.Permission;
import sis.security.PermissionException;
import sis.studentinfo.Account;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class AccountFactoryTest extends TestCase {
    //需要权限的方法列表
    private List<Method> updateMethods;
    //不需要权限的方法列表
    private List<Method> readOnlyMethods;

    protected void setUp() throws Exception {
        //初始化需要权限的列表
        updateMethods = new ArrayList<>();
        addUpdateMethod("setBankAba", String.class);
        addUpdateMethod("setBankAccountNumber", String.class);
        addUpdateMethod("setBankAccountType", Account.BankAccountType.class);
        addUpdateMethod("transferFromBank", BigDecimal.class);
        addUpdateMethod("credit", BigDecimal.class);
        //初始化 不 需要权限的列表
        readOnlyMethods = new ArrayList<>();
        addReadOnlyMethod("getBalance");
        addReadOnlyMethod("transactionAverage");
    }


    public void testUpdateAccess() throws Exception {
        //测试给出的权限 是可以修改的
        Accountable account = AccountFactory.create(Permission.UPDATE);

        for (Method method : readOnlyMethods) {
            verifyNoException(method, account);
        }

        for (Method method : updateMethods) {
            verifyNoException(method, account);
        }
    }

    public void testReadOnlyAccess() throws Exception {

        //给出的权限是 只读的
        Accountable account = AccountFactory.create(Permission.READ_ONLY);
//
        for (Method method : readOnlyMethods) {
            verifyNoException(method, account);
        }


        for (Method method : updateMethods) {
            verifyException(PermissionException.class,method, account);
        }

    }

    //getDeclaredMethod() 获取class中指定方法名,方法参数列表.表示的方法.
    private void addUpdateMethod(String name, Class parmClass) throws Exception {
        updateMethods.add(Accountable.class.getDeclaredMethod(name, parmClass));
    }
    //getDeclaredMethod() 获取class中指定方法名,方法参数列表.表示的方法.
    private void addReadOnlyMethod(String name) throws Exception {
        Class[] noParms = new Class[]{};
        readOnlyMethods.add(Accountable.class.getDeclaredMethod(name, noParms));
    }


    //抛出异常
    private void verifyException(Class exceptionType, Method method, Object object) throws Exception {
        try {
            method.invoke(object, nullParmsFor(method));
        } catch (InvocationTargetException e) {
            System.out.println("不是安全方法抛出异常");
        }
    }

    //将 给定方法 设置到 给定 对象中 不抛出异常
    private void verifyNoException(Method method,Object object)throws Exception{
        try{
            method.invoke(object,nullParmsFor(method));
        }catch (InvocationTargetException e){
            System.out.println(e.getCause());
            assertFalse("unexpected permission exception", PermissionException.class==
                    e.getCause().getClass());
        }
    }

    //参数列表
    private Object[]nullParmsFor(Method method){
        return new Object[method.getParameterTypes().length];
    }
}
